import openai
import requests
from fastapi import HTTPException

from core.config import settings
from models.chat import ChatMessage, ChatSession, ChatApplication
from schemas.chat import ChatApplicationPydanticList


class OpenAiService(object):
    """
    关于openai的服务
    """
    open_key = settings.OPENAI_API_KEY

    def __init__(self, organization=settings.OPENAI_ORGANIZATION, open_ai_key=settings.OPENAI_API_KEY):
        self.chat_openai = openai
        self.chat_openai.api_key = open_ai_key

    @staticmethod
    def init_chat(data, open_ai_key=settings.OPENAI_API_KEY):
        # completion = openai.ChatCompletion.create(
        #     model="gpt-3.5-turbo",
        #     messages=[
        #         {"role": "user", "content": "Hello!"}
        #     ]
        # )
        print(open_ai_key)
        chat_openai = openai
        chat_openai.api_key = open_ai_key
        completion = chat_openai.ChatCompletion.create(
            model=data["model"],
            messages=data["messages"]
        )
        return completion

    @staticmethod
    async def send_message(message, chat_session=None):
        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {settings.OPENAI_API_KEY}'
        }
        data = {
            "model": "gpt-3.5-turbo",
            "messages": message
        }
        try:
            # res = requests.post('https://api.openai.com/v1/chat/completions', headers=headers, json=data,
            #                     timeout=120)
            # if res.status_code != 200:
            #     raise HTTPException(status_code=400, detail="Request failed, please try again")
            # completion = res.json()
            completion = OpenAiService.init_chat(data)
        except Exception as e:
            print(str(e))
            raise HTTPException(status_code=400, detail="Request failed, please try again")
        content = completion['choices'][0]['message']['content'].strip()
        role = completion['choices'][0]['message']['role']
        data = {
            "content": content,
            "role": role,
        }
        if chat_session:
            await ChatService.save_message(chat_session, message[-1]['role'], message[-1]['content'],
                                           ChatMessage.MESSAGE_ACTION_USER)
            await ChatService.save_message(chat_session, role, content, ChatMessage.MESSAGE_ACTION_AI)
            data["sub"] = {
                "id": chat_session.id,
                "title": chat_session.session_title,
            }
        return data, completion


class ChatService(object):
    """

    """

    @staticmethod
    async def get_session(chat_id, chat_title, user, new=False):
        chat = None
        if chat_id:
            chat = await ChatSession.filter(pk=chat_id, user_id=user).first()
        if not chat:
            chat = await ChatSession.create(
                session_title=chat_title[:100] if len(chat_title) > 100 else chat_title,
                user_id=user
            )
            new = True
        return chat, new

    @staticmethod
    async def save_message(chat_session, role, message, action):
        chat_message = await ChatMessage.create(
            content=message,
            message_action=action,
            owner_chat=chat_session,
            role=role
        )
        return chat_message

    @staticmethod
    async def combination_information(message_items):
        # chat_message_items = await ChatMessagePydanticList.from_queryset(message_items.values("role", "message"))
        # chat_message_items = await message_items.order_by("-created_at").values("role", "message")
        return await message_items.order_by("created_at").values("role", "content")

    @staticmethod
    async def compose(chat_message, chat_session):
        chat_message_items = ChatMessage.filter(owner_chat=chat_session.id)
        information = await ChatService.combination_information(chat_message_items)
        information.append({"role": "user", "content": chat_message.message})
        return information

    @staticmethod
    async def save_session(completion, chat_session):
        chat_session.model = completion['model']
        chat_session.object = completion['object']
        await chat_session.save(update_fields=["model", "object"])


class ChatApplicationService(object):

    @staticmethod
    async def save_application(data):
        chat_app = await ChatApplication.create(**data)
        return chat_app

    @staticmethod
    async def get_application_info(application_id):
        application = await ChatApplication.filter(pk=application_id).first()
        if not application:
            raise HTTPException(status_code=400, detail="No Such App")
        return application

    @staticmethod
    async def search_application(search_value, user):
        application_items = ChatApplication.filter(application_type=ChatApplication.APPLICATION_TYPE_PUBLIC)
        if search_value:
            application_items = application_items.filter(title__icontains=search_value)
        private_items = None
        if user:
            private_items = ChatApplication.filter(user_id=user.id,
                                                   application_type=ChatApplication.APPLICATION_TYPE_PRIVATE,
                                                   title__icontains=search_value)
        application_pydantic = await ChatApplicationPydanticList.from_queryset(application_items)
        application_list = application_pydantic.dict()["__root__"]
        if private_items:
            private_pydantic = await ChatApplicationPydanticList.from_queryset(private_items)
            application_list.extend(private_pydantic.dict()["__root__"])
        return application_list

    @staticmethod
    async def search_my_application(search_value, user):
        if user:
            if search_value:
                private_items = ChatApplication.filter(user_id=user.id,
                                                       title__icontains=search_value)
            else:
                private_items = ChatApplication.filter(user_id=user.id)
            private_pydantic = await ChatApplicationPydanticList.from_queryset(private_items)
            return private_pydantic.dict()["__root__"]
        raise HTTPException(status_code=400, detail="Invalid user")
